#include <rthw.h>
#include <ulog.h>
#include <dfs_posix.h>
#include <rtthread.h>

#ifdef LOG_USING_FILTER
#include "api/log_api.h"
#endif /* LOG_USING_FILTER */


#undef LOG_TAG
#undef LOG_LVL
#define LOG_TAG     "logfile"
#define LOG_LVL     LOG_LVL_DBG

#ifdef ULOG_BACKEND_USING_FILE

#define LOG_FILE_NAME_MAX              50
#define FILE_LOG_ROOT_PATH             "/"
#define USER_LOG_PATH                  "/log/"
#define USER_LOG_NAME                  "pm"
#define FILE_LOG_TYPE                  ".log"
#define FILE_SIZE_MAX                  (512 * 1024)
#define FILE_LOG_NUM_MAX                5

static struct ulog_backend ulog_file;
int g_ulog_fd = -1;

static struct rt_mutex log_file_lock;

rt_bool_t check_file_path(const char *root_path, const char *file_path)
{
    if (root_path == NULL || file_path == NULL)
    {
        rt_kprintf("check_file_path: error! the root path is %s, file path is %s\n", root_path, file_path);
        return RT_FALSE;
    }

    if (access(root_path, 0) != 0)
    {
        rt_kprintf("check_file_path: error! the root path %s does not exist\n", root_path);
        return RT_FALSE;
    }

    if (access(file_path, 0) != 0)
    {
        if (mkdir(file_path, 0777) == -1)
        {
            rt_kprintf("check_file_path: error! the file_path path %s does not exist\n", file_path);
            return RT_FALSE;
        }
    }
    return RT_TRUE;
}

rt_bool_t check_file_handle(int fd)
{
    if (fd >= 0)
        return RT_TRUE;
    return RT_FALSE;
}

/* get log file fd : st apollo pms */
int get_file_handle(void)
{
    char file_name[LOG_FILE_NAME_MAX] = {0};
    rt_bool_t result = RT_FALSE;
    static rt_bool_t check_dir = RT_FALSE;

    if (!check_dir)
    {
        result = check_file_path(FILE_LOG_ROOT_PATH, USER_LOG_PATH);
        if (result == RT_FALSE)
        {
            rt_kprintf ("log path is not exsit\n");
            return -1;
        }
        check_dir = RT_TRUE;
    }

    rt_mutex_take(&log_file_lock, RT_WAITING_FOREVER);

    if (!check_file_handle(g_ulog_fd))
    {
        rt_snprintf(file_name, LOG_FILE_NAME_MAX - 1, "%s%s%s",
            USER_LOG_PATH,USER_LOG_NAME,FILE_LOG_TYPE);

        g_ulog_fd = open(file_name, O_CREAT | O_RDWR);

        if(g_ulog_fd < 0)
        {
            rt_kprintf ("log file open error,fd=%d!!\n", g_ulog_fd);
        }
    }

    rt_mutex_release(&log_file_lock);

    return g_ulog_fd;
}

int get_log_file_number(const int number, const char *path)
{
    char file_name[LOG_FILE_NAME_MAX] = {0};
    int status = -1;
    int file_num = 0;

    for (int32_t i = number; i > 0; i--)
    {
        rt_memset(file_name, 0, LOG_FILE_NAME_MAX);
        rt_snprintf(file_name, LOG_FILE_NAME_MAX - 1, "%s%s_%d%s",
            path, USER_LOG_NAME, i, FILE_LOG_TYPE);

        status = access(file_name, 0);
        /* get file max log number */
        if (status == 0)
        {
            file_num = i;
            break;
        }
    }
    return file_num;
}

int log_file_rename(int max_index, const char *path, const int max_number, const char *file_name)
{
    int32_t i = 0;
    int ret = 0;
    char old_file_name[LOG_FILE_NAME_MAX] = {0};
    char new_file_name[LOG_FILE_NAME_MAX] = {0};

    if (max_index >= max_number)
    {
        char max_index_file[LOG_FILE_NAME_MAX] = {0};
        rt_snprintf(max_index_file, LOG_FILE_NAME_MAX - 1, "%s%s_%d%s",
            path, USER_LOG_NAME, max_number, FILE_LOG_TYPE);
        unlink(max_index_file);
    }
    else
    {
        max_index++;
    }

    for (i = max_index; i > 1; i--)
    {
        rt_memset(old_file_name, 0, LOG_FILE_NAME_MAX);
        rt_memset(new_file_name, 0, LOG_FILE_NAME_MAX);
        rt_snprintf(new_file_name, LOG_FILE_NAME_MAX - 1, "%s%s_%d%s",
            path, USER_LOG_NAME, i, FILE_LOG_TYPE);

        rt_snprintf(old_file_name, LOG_FILE_NAME_MAX - 1, "%s%s_%d%s",
            path, USER_LOG_NAME, i - 1, FILE_LOG_TYPE);

        ret = rename(old_file_name, new_file_name);

        if(ret != 0)
        {
            rt_kprintf ("file rename error:%s\n",old_file_name);
        }
    }

    rt_memset(old_file_name, 0, LOG_FILE_NAME_MAX);
    rt_memset(new_file_name, 0, LOG_FILE_NAME_MAX);
    rt_snprintf(old_file_name, LOG_FILE_NAME_MAX - 1, "%s", file_name);
    rt_snprintf(new_file_name, LOG_FILE_NAME_MAX - 1, "%s%s_%d%s",
        path, USER_LOG_NAME, i, FILE_LOG_TYPE);

    ret = rename(old_file_name, new_file_name);
    if(ret != 0)
    {
      rt_kprintf ("file rename error:%s\n",old_file_name);
    }
    return ret;
}

void log_file_rename_all(const char *path, const int32_t max_number)
{
    char file_name[LOG_FILE_NAME_MAX] = {0};
    int32_t max_index = 0;

    max_index = get_log_file_number(max_number, path);
    rt_snprintf(file_name, LOG_FILE_NAME_MAX - 1, "%s%s%s",
        path, USER_LOG_NAME, FILE_LOG_TYPE);

    log_file_rename(max_index, path, max_number, file_name);
}

void close_log_file_handle(void)
{
    if (check_file_handle(g_ulog_fd))
    {
        close(g_ulog_fd);
        g_ulog_fd = -1;
    }
}

void log_file_handle_update(int fd)
{
    g_ulog_fd = fd;
}

void ulog_file_backend_output(struct ulog_backend *backend, rt_uint32_t level,
    const char *tag, rt_bool_t is_raw, const char *log, size_t len)
{
    off_t file_size = 0;
    int fd = -1;
    int32_t buf_len = 0;
    int32_t offset = 0;

    fd = get_file_handle();

    if (fd < 0)
    {
        rt_kprintf ("get_file_handle fail: %d.\n", fd);
        return;
    }
    for (buf_len = len; buf_len > 0; buf_len -= ULOG_LINE_BUF_SIZE)
    {
        file_size = lseek(fd, 0, SEEK_END);
        if (file_size > FILE_SIZE_MAX) /* log file max size check*/
        {
            close(fd);
            fd = -1;
            log_file_handle_update(fd);
            log_file_rename_all(USER_LOG_PATH, FILE_LOG_NUM_MAX);
        }

        if (fd < 0)
        {
            fd = get_file_handle();
            if (fd < 0)
            {
                rt_kprintf("new file get_file_fd fail: %d.\n", fd);
                return;
            }
        }

        if (buf_len < ULOG_LINE_BUF_SIZE)
        {
            write(fd, log + offset, buf_len);
            offset += buf_len;
        }
        else
        {
            write(fd, log + offset, ULOG_LINE_BUF_SIZE);
            offset += ULOG_LINE_BUF_SIZE;
        }
        fsync(fd);
    }
}

int ulog_file_backend_init(void)
{
    /* create device filesystem lock */
    rt_mutex_init(&log_file_lock, "logfile", RT_IPC_FLAG_FIFO);

    ulog_init();
    rt_thread_mdelay(1000);
    ulog_file.output = ulog_file_backend_output;
    ulog_backend_register(&ulog_file, "file", RT_FALSE);

    return 0;
}

//INIT_APP_EXPORT(ulog_file_backend_init);

#endif /* ULOG_BACKEND_USING_FILE */
